/*
 * ExtensionElement.java
 *
 * Created on August 22, 2006, 3:45 AM
 *
 * @author Francois Daniels
 */

package za.gateway.container;

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Hashtable;
import java.util.Enumeration;
import za.gateway.container.SingleExtentionsEntry;
import za.gateway.preferences.Settings;

/**
 * This class is used in the creation of the dial plans. Its main task 
 * is to store and arrange the elements in preparation for output in 
 * the particular group's context. The items in the dial plan are 
 * arranged in such a manner that all the FORWARD rules are checked 
 * first. The ALLOW rules will be checked next. If a rule that allows 
 * explicit access to a number does not exist within a context, then 
 * that group will be denied access by default.
 *
 * @author Francois Daniels
 */
public class ExtensionElement {
    /**
     * This is the phone number to which this restriction applies to.
     */
    protected String PhoneNumber;
    
    /**
     * This is the time at which this restriction becomes valid
     */
    protected int StartTime;
    
    /**
     * This is the time at which this restriction is no longer valid
     */
    protected int EndTime;
    
    /**
     * This is merely the type of the restriction. ALLOW and FORWARD
     * conditions have different priorities. This allows us to sort the 
     * queue by basing its priority on the <B>type</B> of the 
     * restriction.
     */
    protected int Priority;
    
    /**
     * This table holds the list of elements which we are going to 
     * write to the output file. The entries are hashed by username. 
     * This means each user will have a context, and thus access 
     * permissions of their own.
     **/
    protected Hashtable Table;
    
    /**
     * This queue will be used to arrange the elements in order of 
     * priority. This is done so that items with FORWARD conditions are 
     * evaluated before ALLOW conditions.
     */
    protected PriorityQueue<SingleExtentionsEntry> Pqueue;
    
    /** Creates a new instance of ExtensionElement */
    public ExtensionElement () {
        Table = new Hashtable ();
    }
    
    /**
     * This adds a restriction to this container. The restriction is 
     * added to this class' internal list and ordered based on its 
     * type.
     *
     * @param PhoneNum  This is the phone number to which the call is 
     *                  being placed.
     * @param StartTime This is the time at which this restriction 
     *                  becomes active.
     * @param EndTime   This is the time at which this restriction 
     *                  deactivates itself.
     * @param Type      This is the type of the restriction. It can be 
     *                  of type FORWARD or ALLOW.
     * @param Forward   This is the number to which this number should 
     *                  be forwarded if this restriction is of type 
     *                  FORWARD.
     * @param StartDay  This is the Day on which this restriction 
     *                  becomes active.
     * @param EndDay    This is the Day on which this restriction 
     *                  deactivates.
     */
    public void add (String PhoneNum, int StartTime, int EndTime, 
            int Type, String Forward, String StartDay, String EndDay) {
        
        // We create a priority queue to arrange the elements by the
        // type of this restriction
        Pqueue = (PriorityQueue<SingleExtentionsEntry>) 
            Table.get (PhoneNum);
        
        // If the queue has not been created yet we create a new one
        if (Pqueue == null) {
            Pqueue = new PriorityQueue<SingleExtentionsEntry>(20,
                    new Comparator<SingleExtentionsEntry>() {
                
                public int compare (SingleExtentionsEntry i, 
                        SingleExtentionsEntry j) {
                    
                    if (i.GetPriority () == j.GetPriority ())
                        return 0;
                    if (i.GetPriority () > j.GetPriority ())
                        return -1;
                    return 1;
                }
            }
            ); 
        }        
        
        // We add this element to the queue
        Pqueue.add (new SingleExtentionsEntry (Type, StartTime, 
                EndTime, Forward, StartDay, EndDay));
        
        // We save the queue in the hash table
        Table.put (PhoneNum, Pqueue);
    }
    
    /**
     * This function converts this object to type String.
     *
     * @return The string representation of this object.
     */
    public String toString () {
        String contents = new String ();        
         for (Enumeration Keys = Table.keys (); 
            Keys.hasMoreElements ();) {
            
            String Key = Keys.nextElement ().toString ();
            
            PriorityQueue<SingleExtentionsEntry> pq = (
                    PriorityQueue<SingleExtentionsEntry>) 
                    Table.get (Key);
            
            if (pq == null) return "";
            
            SingleExtentionsEntry [] e = pq.toArray (
                    new SingleExtentionsEntry [pq.size ()]);
            
            // We extract each element from the queue
            for (int k = 0; k < e.length; k++) {
                SingleExtentionsEntry Entry = e[k];
                String Time = new String ();
                
                String StartDay = e [k].GetStartDay ();
                String EndDay = e [k].GetEndDay ();
                String Days = new String ();
                
                if (e[k].GetStartTime () == e[k].GetEndTime ()) {
                    Time = "*";
                }
                else {
                    Time = "TODO: SPECIFY";
                }
                
                if (StartDay.equals ("") || EndDay.equals ("")) {
                    Days = "*";
                }
                else {
                    Days = StartDay +"-"+ EndDay;
                }
                
                // We add this dial rule to our string
                contents += "exten => "+Key+","+(k+1)+",GotoIfTime("+
                        Time+"|"+Days+"|*|*?system_dial,"+
                        Entry.GetDialout ()+",1)\n";
            }
         }
        
        // We end this context with the default rule
        contents += "exten => _X.,1,Playback("+Settings.invalidNumber+
                ")\n" + "exten => _X.,2,Hangup()\n";
            
        return contents;
    }
    
}
